//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <ddk.h>
#include <bulverde.h>
#include "ssp.h"

static DzMutex s_sspLock;

EXTERN_C void SSP_GPIO(void)
{
	//GPSR0 = (1<<23)|(1<<24)|(1<<25);
	GPDR0 &=~ ((1<<26)|(1<<14));//input
	GPDR0 |=(1<<23)|(1<<24)|(1<<25);//output
	GAFR0_U |=(2<<14)|(2<<16)|(2<<18)|(1<<20);


}
EXTERN_C void SSP_Initial(void)
{
#define DIVIDE  (4*1024-1)
	SSP_GPIO();

    CLK_SSP1_DISABLE;

    BV_SSCR0_1 =   (DIVIDE*SSCR0_SCR)  |   // SSPSCLK: 13M/(DIVIDE+1) = 1MHz
                    (15*SSCR0_DSS)      |   // (15+1) bits/WORD
                    (0*SSCR0_FRF);          // Motorola SPI

    BV_SSCR1_1 =   (8*SSCR1_TX_THRESSHOLD)|(8*SSCR1_RX_THRESSHOLD) |
                    (1*SSCR1_SPH) | (0*SSCR1_SPO);  // idle low, falling for sample

//    BV_SSITR_1 =;
//    BV_SSTO_1  =;
//    BV_SSPSP_1 = (1*SSPSP_SCMODE);     // SCMODE: 1

    BV_SSCR0_1 |=  SSCR0_SSE;
}

unsigned long SSP_Exchange(unsigned short * pData, unsigned long dwNum)
{
    unsigned long i;
    WaitResult wr;

    if( (dwNum == 0)                    ||
        (dwNum > (SSP_FIFO_DEEP - 1))  )       // '-1' to simplify the software: need not to test the SSSRx[TNF] & SSSRx[RNE]
    {   // too long to fill into FIFO
        return 0;
    }

    s_sspLock.Lock(&wr);

    if( (BV_SSSR_1 & SSSR_BSY)||
        (BV_SSSR_1 & ((SSP_FIFO_DEEP - 1) * SSSR_TFL)) )
    {   // there are still some data in TX FIFO
        // or SSP is active now
        s_sspLock.Unlock();
        return 0;
    }

    for(i=0;i<dwNum;i++)
    {
        BV_SSDR_1  = pData[i];
    }

    CLK_SSP1_ENABLE;

    while( (BV_SSSR_1 & SSSR_BSY) || (BV_SSSR_1 & ((SSP_FIFO_DEEP - 1) * SSSR_TFL)))
    {   // wait until FIFO is empty & SSP is idle
        // make sure GP024_SSPSFRM is high
        DzSleep(1, NULL); // NOTE: Not invoked in ISR
    }

    CLK_SSP1_DISABLE;

    i = ((BV_SSSR_1) & ((SSP_FIFO_DEEP - 1) * SSSR_RFL)) / SSSR_RFL;
    i++;

    if(i < dwNum)
    {   // receive length error
        dwNum = i;
    }

    for(i=0;i<dwNum;i++)
    {
        pData[i] = (unsigned short)BV_SSDR_1;//BUGBUG: pData is 16bits ???
    }

    s_sspLock.Unlock();

    return dwNum;
}
